iT邦幫忙

2022 iThome 鐵人賽

DAY 25
0
自我挑戰組

JavaScript101與人生幹話系列 第 27

JavaScript101與人生幹話-運算子、型別與文法

  • 分享至 

  • xImage
  •  

1.陳述式(Statmene)與表達式(Expression)

陳述式(Statmene):執行JS的指令的語句,不會回傳結果。
例如:

// 流程控制
if else
break

// 宣告
var
const
let

// 指定含式類別
function

// 迭代
for

表達式(Expression):又稱運算式,透過上下的語句與符號運算並回傳結果/取得一個值。
例如:

// 雖然這個運算是沒有指定變數來儲存值。
123 + 13;
// 賦值是一種表達式
string = 'string'

2.函式陳述式與函式表達式

函式陳述式:直接使用function宣告的函式,又稱具名函式。
例如:

function myFunction() {
    
}

含式表達式:宣告一個變數並賦值函數。
例如:

// 後面沒有名稱的是匿名含式
var callFunction = function(){
    
}

3.ASI(Automatic Semicolon Insertion) 自動插入分號

先看個範例

function callJack() {
    return
    'Jack';
}
console.log(callJack()) // undefined

在修改為

function callJack() {
    retrun 'Jack';
    
}
console.log(callJack()) // 'Jack'

會有開頭那個範例的問題是因為,ASI為自動把語句的結尾加上;
所以開頭的範例實際上是

function callJack() {
    // rerurn後面直接上加上分號,所以沒有return任何東西
    return;
    'Jack';
}
console.log(callJack()) // undefined

立即函式間的;

(function(){
    console.log('立刻執行')
}())
(function(){
    console.log('立刻執行2')
}())

以上程式碼會報錯,ASI並不會自動加入;
必須加入分號才會順利執行

(function(){
    console.log('立刻執行')
}()); // 這裡加分號
(function(){
    console.log('立刻執行2')
}())

// '立刻執行'
// '立刻執行2'

容易出錯的範例

let a = 1
(function(){
    console.log(a)
})()
//1 is not a function

會出現上面的錯誤是因為,在新的一行開頭為

( [ / + - * % , .

時上一行式不會自動加入分號的。
也就是說實際執行是

let a = 1(function(){console.log(a)})()

修改方式為以下

let a = 1;
(function(){
    console.log(a)
})() // 1

4.動態型別

JavaScript在執行的時候才會賦予確認的型別。
例如:

let string = '文字'
console.log(typeof string) // "string"
string = 1
console.log(typeof string) // "number"

可以觀察到變數string賦值1的時候型別就從字串轉成數字。

4-1顯性的轉換(Explicit conversion)

上述的範例就是顯性轉換的例子

4-2隱性的轉換(Implicit conversion)

let num = 123
console.log(num, typeof num) // 123  "number"

num = num + ''
console.log(num, typeof num) // '123' "string"

num = num / 1
console.log(num, typeof num) // 123 "number"

從上面的範例看到num這個變數的型別經過運算後被改變,這就是隱性的轉換。

5.原始型別及物件型別

5-1原始型別

字串(string)
數字(number)
布林(boolean)
未定義(undefined)
空(null)
Bigint
Symbol

其中只有null與undefined沒有包裹物件。
包裹物件就是讓原始型別有一些方法能夠使用,例如大小寫轉換。

let a = 'a'
let A = new String(a)
console.log(A) // String {'a'}

點擊String {'a'}後再點擊Prototype就可以查到,包裹物件的方法

不過包裹物件的型別是物件,是建構式,一般宣告普通型別時不會這樣子用。

6.運算子

6-1一元運算子

delete
// 用來刪除物件、物件屬性、或陣列中指定的index
typeof
// 用來回傳代表運算元類型

6-2三元運算子

let condiction = true
console.log(condiction? 'go':'stop') // 'go'
//?前為判斷式,結果為true的話就會執行:左邊,如果是false則執行:右邊

6.優先性(Precedence)及相依性(Associativity)

優先性(Precedence):運算子間優先度的順序。
相依性(Associativity):決定運算方向。

運算子優先序

可以參考連結中的table,其中數字越大代表優先度越高,如果優先度相同則依照相依性的方向執行。

以下為等號的相依性為例子
等號的相依性由右至左

const obj = {}
Object.defineProperty(obj, 'a',{
  value:1,
  writable:false
})
obj.a = 5
// 現在obj.a 無法被寫入
console.log(obj.a) // 1
Object.defineProperty(obj, 'b',{
  value:3,
  writable:false
})

let a = 2
a = obj.b = obj.a = 100
// obj.a = 100 為表達式,會回傳100,但是obj.a在上面設定不可寫入,所以沒辦法被賦值,obj.b也相同,最後a被賦值是obj.a = 100的回傳值。
console.log(a) // 100
console.log('obj.a', obj.a) // 1
console.log('obj.b', obj.b) // 3

a = obj.b = obj.a = 100
如果照步驟拆開來看就是
obj.a = 100 為表達式回傳100,但是obj.a不會被寫入回傳值所以
obj.b = 100 為表達式回傳100,但是obj.b不會被寫入回傳值所以
a = 100 為表達式回傳100,a被賦值回傳的數值。

7.寬鬆相等、嚴格相等以及隱含轉型

7-1、嚴格相等

嚴格相等會先判斷資料的型別,再判斷資料的值是否相同。
例如:

console.log(1 === 1) // true
console.log('2' === '2') // true
console.log(1 === '1') // false

不過也有例外的時候
例如:

console.log(NaN === NaN) // false
console.log(+0 === -0) // true
console.log(undefined === null) // false

7-2寬鬆相等

console.log('1' == 1) // true
console.log(true == 1) // true
console.log(true == '1') // true
console.log(true == 'true') //false
// 因為true會被轉為1, 'true'則是無法轉為數字,結果為NaN,所以結果為false

以上範例會將布林與字串轉為數字後做比較。
再寬鬆相等時 true '1'會轉換為1,false與'0'則轉換為0

再來看看比較特別的範例

console.log('1' == !0) // true

'1'轉換為數字1
!0 轉換為 true,再轉換為1

console.log(!0) // true

7-3 null、undefined的寬鬆相等

console.log(Number(null)) // 0
console.log(Number(undefined)) // NaN

雖然null使用Number轉型是轉型為0但是,再寬鬆相等的情況下不轉型。

console.log(null == 0) // false
console.log(undefined == 0) // false

再來是與嚴格相等不同的是再寬鬆相等的情況下null等於undefined

console.log(undefined == null) // true

7-4物件與非物件的寬鬆相等

物件與非物件比較時,使用包裹物件做轉換。

console.log(1 == [1]) // true
console.log('1' == [1]) // true
console.log(true == [1]) // true

上面範例中的[1]會使用包裹物件轉型為數字後比較。

console.log('a' == ['a']) // true

與數字的範例相同,也是同樣用包裹物件轉型為字串後比較。

物件與物件間的比較

console.log([] == []) // false
console.log({} == {}) // false

會出現false的原因是物件比較的不是值,是參考位置,也就是不同的物件所存放的記憶體空間不同。

const a = {}
const b = a
console.log(a === b) // true
console.log(a == b) // true

因為a 與 b的參考位置相同所以比較結果為true。

8-1真值(truthy)與假值(falsy)

與自動轉型不同

if(5) {
    console.log('我執行了')
}
// "我執行了"
console.log(5 == true)  // false

上面的例子中if條件內的5是真值,與寬鬆比較把true轉為1不同。

延伸閱讀

A standard IF statement

9.邏輯運算子及函式預設值

&&、||、!

用來驗證兩個值是否為真值

9-1&&

(Expression1 && Expression2)
Expression1為falsy則回傳Expression1,Expression1為truthy則回傳Expression2,如果都是boolean則是兩者都是true才會回傳true,否則回傳false。

9-2||

(Expression1 || Expression2)
Expression1為thruthy,回傳Expression1,Expression1為falsey回傳Expression2,如果都是boolean則是其中之一只要是true季就回傳true,兩者都是false才會回傳false。

9-3!

truthy轉為falsy,falsy轉為truthy。

特別的例子

let money = 500
function saveMoney(data) {
     data = data || 100
     console.log(`現在有${money + data}`)
    
}
saveMoney() // "現在有600"

但是以上的範例如果saveMoney(0)就會出現NaN
需要使用三原運算做修改,

let money = 500
function saveMoney(data) {
     (data===undefined || data===0)? data=0 : data
     console.log(`現在有${money + data}`)
}
saveMoney(0) // "現在有600"

也可以使用if條件式,兩者意思相同。

let money = 500
function saveMoney(data) {
     if(data===undefined || data===0){
         data = 0
     }
     console.log(`現在有${money + data}`)
}
saveMoney(0) // "現在有600"

人生幹話-想找人當長工,你有更好的方法

還有在QA工作有兩個主管,一位是經理、另一位是副經理,兩者都不是好主管,經理呢舌燦蓮花,把黑的說成白的,畢竟傳產尿性就是這樣你知道他在講幹話,你反駁他也沒用,畢竟他職位比你大,另一位副經理遇到事情就是推、拖、閃,一心只想完成他的學業而以,還有他的法規顧問夢,不知道是風險管理這個職位的流動率太高還是真的太為下屬著想,經理一直鼓勵我快買房,買房當然不錯啊但有沒有想過我一個月實領不到3萬,寬限期過之後房貸一個月要還3萬5,做一個月沒辦法吃飽就算了還倒貼,更瞎的是一直鼓勵去借錢玩當沖,說當沖零成本之類的幹話,想把人綁下來當長工有沒有考慮過更不缺德的方法呢?例如加薪。


上一篇
JavaScript101與人生幹話-函式、閉包、This與simple call
下一篇
JavaScript101與人生幹話- 繼承與原型鍊
系列文
JavaScript101與人生幹話30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言